import axios, { AxiosError, AxiosRequestConfig, AxiosResponse } from 'axios'
import { ElMessage, ElMessageBox } from 'element-plus'
import { refreshToken } from '../api/user'
import { useUserStore } from '../store/modules/user'
import { usePermissionStore } from '../store/modules/permission'
import router from '../router/index'
import _ from 'lodash'
import { closeWebSocket } from '../utils/socket'

let isRefreshing = false
let refreshSubscribers: Array<(token: string) => void> = []
let isErr = true
// 过期提醒
const returnTip = _.debounce(
  (tip) => {
    closeWebSocket()
    const UserStore = useUserStore()
    window.localStorage.removeItem('ddUserState')

    UserStore.token = null
    UserStore.roles = []
    UserStore.row = {
      tokenValue: null, //登录token
      expireIn: null, //过期时间
      tokenStartTime: null, //登录当前时间
      refreshToken: null, //刷新token
      tokenName: null,
    }
    ElMessageBox.confirm(tip, '温馨提示', {
      confirmButtonText: '确定',
      type: 'error',
      showCancelButton: false,
      showClose: false,
      closeOnClickModal: false,
      closeOnPressEscape: false,
    }).then(() => {
      usePermissionStore().clearRoutes()
      router.push({ path: '/login/index' })
    })
  },
  800,
  { leading: false },
)

// 创建axios实例 进行基本参数配置
const service = axios.create({
  // 默认请求地址，根据环境的不同可在.env 文件中进行修改
  // baseURL: import.meta.env.VUE_APP_BASE_API,
  baseURL: import.meta.env.VITE_APP_BASE_API,
  // 设置接口访问超时时间
  timeout: 300000, // request timeout，
  // 跨域时候允许携带凭证
  withCredentials: true,
})

// 不需要刷新token的接口
const refreshTokenWhiteUrlList = [
  '/system/login/',
  '/system/login/logout',
  '/sms/loginCode',
  '/sms/registerCode',
  '/sms/updateCode',
  '/system/account/notLoginUpdatePassword',
  '/system/account/register',
  '/system/login/getCustomer',
  '/system/login/getCustomerCode',
  '/system/customer/register',
  '/system/account/getInfo',
]

/**
 * 请求拦截
 */
service.interceptors.request.use(
  (config: AxiosRequestConfig) => {
    if (config.headers) {
      config.headers = {}
    }

    if (config.headers && config.headers['access-token']) {
      delete config.headers['access-token']
    }
    const UserStore = useUserStore()
    /**
     * 用户登录之后获取服务端返回的token,后面每次请求都在请求头中带上token进行JWT校验
     * token 存储在本地储存中（storage）、vuex、pinia
     */
    // let token = UserStore.token
    const token: string = UserStore.row.tokenValue || ''
    if (config.headers && UserStore.row.tokenName) {
      config.headers[UserStore.row.tokenName] = token
    }

    // 请求白名单里面的请求跳过刷新
    if (config.url && refreshTokenWhiteUrlList.includes(config.url)) {
      return config
    }

    /**
     * 判断是否刷新token，如果为正在刷新token，且请求为刷新token的路径，则直接放行
     */
    if (config.url == '/system/login/refreshToken') {
      return config
    }

    // 获取存储token的开始时间
    const tokenStartTime = UserStore.row.tokenStartTime

    // 后台给出的token有效时间，一个星期 单位 是秒
    const timeOver = (UserStore.row.expireIn || 60 * 60 * 24 * 7) * 1000

    // 当前时间
    const date = new Date().getTime()

    if (token) {
      //10分钟内刷新token
      if (
        tokenStartTime &&
        timeOver - 10 * 60 * 1000 < date - tokenStartTime &&
        date - tokenStartTime < timeOver
      ) {
        if (!isRefreshing) {
          isRefreshing = true
          refreshToken({ refreshToken: UserStore.row.refreshToken }).then((res) => {
            UserStore.token = res.data.data.row.tokenValue
            UserStore.row = { ...res.data.data.row, tokenStartTime: new Date().getTime() }
            refreshSubscribers.forEach((cb) => cb(res.data.data.row.tokenValue))
            refreshSubscribers = []
            isRefreshing = false
          })
        }

        // 返回未执行 resolve 的Promise
        const retryOriginalRequest = new Promise((resolve) => {
          // 用函数形式 将resolve 存入，等待刷新后再执行
          refreshSubscribers.push((token: string) => {
            if (config.headers && UserStore.row.tokenName) {
              config.headers[UserStore.row.tokenName] = token
            }
            resolve(config)
          })
        })

        // 返回config，继续原始请求
        return retryOriginalRequest
      }
      // if (tokenStartTime && date - tokenStartTime > timeOver) {
      //   returnTip('登录状态过期，请重新登录')
      //   return Promise.reject()
      // }
      return config
    }
    return config
  },
  (error: AxiosError) => {
    // 请求错误，这里可以用全局提示框进行提示
    showErrMessage('服务器处理繁忙，请稍后重试！')
    return Promise.reject(error)
  },
)

/**
 * 响应拦截
 */
service.interceptors.response.use(
  (response: AxiosResponse) => {
    // 错误提醒
    if (response.data.code == 40100 || response.data.code == 41000) {
      returnTip(response.data.message)
      response.data['isError'] = false
      return response
    } else if (response.data.code == 40101) {
      returnTip(response.data.message)
      response.data['isError'] = false
      return response
    } else if (response.data.code == 40102) {
      returnTip(response.data.message)
      response.data['isError'] = false
      return response
    } else {
      response.data['isError'] = true
      return response
    }
    // 直接返回res，当然你也可以只返回res.data
    // 系统如果有自定义code也可以在这里处理
  },
  (error: AxiosError) => {
    // 处理响应错误，比如根据状态码进行不同的操作
    showErrMessage('服务器处理繁忙，请稍后重试！')
    return Promise.reject(error)
  },
)

/**
 * @description 显示错误消息
 * opt 传入参数
 * err 错误信息
 * type 消息类型
 * duration 消息持续时间
 */
const showErrMessage = (msg: string, duration = 4000) => {
  if (isErr) {
    isErr = false
    ElMessage({
      message: msg,
      type: 'error',
      duration: duration,
    })
  }
  setTimeout(() => {
    isErr = true
  }, duration)
}

export default service
